# -*- coding: utf-8 -*-
import aima.search as s
#Basicamente el estado lo definimos como una tupla  de 3 elementos enteros en que torre esta ubicado el anillo.
#Cada item del estado indica (AnilloGrande, AnilloMediano, AnilloPequeño) //Podemos agregar anillos ampliando el estados
#No hace falta guardar mas nada, pues sabremos que orden tiene pues son apilables de solo una manera.
class sonsin(s.Problem):#Redefinimos la clase problem
    def __init__(self, initial, goal=None):
        self.initial = initial
        self.goal = goal
        self.CANT_TORRES= 3 #Segun la cantidad de torres que queremos modificaremos aqui. (siempre restar 1)
        self.TORRES= range(0,self.CANT_TORRES)
    def colectora(self, torre, estado):#Devuelve el indice que referencia al anillo movible en una torre
        value= self.CANT_TORRES #En caso de no encontrar ninguno, simplemente quedara el elemento fuera de rango
        for anillo in self.TORRES: #recorreremos la lista de anillos (Necesitamos el indice, por eso recorremos asi).
            if (estado[anillo]==torre): value= anillo #Buscando el ultimo que este en esa torre
        return value #y lo devolvemos, si no hay en esa torre, devuelve 3 y despues no recorre nada :P
    def receptores(self, anillo, estado): #Retorna las torres donde puede moverse un anillo
        posibles_torres= range(0, self.CANT_TORRES) #Empezamos con la posibilidad de moverlo a todos los lugares
        for torre in range(anillo, self.CANT_TORRES): #recorremos todos los anillos mas pequeños al que queremos mover
            if (estado[torre] in posibles_torres): posibles_torres.remove(estado[torre]) #y quitamos la posibilidad de moverlo por ser mas grande ahi
        return posibles_torres #devolvemos la lista de las posibles finalmente!
    def nuevo_estado(self, anillo, proximo, estado): #Crea el proximo sucesor para cargar en lista, estado lo recibe como lista para poder modificarla
        if not(anillo == 3):estado[anillo]=proximo #Simplemente movemos el anillo a la proxima posicion
        return ("M"+(str(anillo)+"a"+str(proximo)),tuple(estado)) #Devuelve una tupla con string que denomina accion y estado nuevo.
    def successor(self, e): #Funcion que genera todos los posibles nuevos estados a los que puede pasar un nodo.
        res= [] 	#Creamos la lista de sucesores para el estado actual.
        for torre in self.TORRES: #recorremos la lista de las torres
            for proximo in self.receptores(self.colectora(torre,e),e): #buscando por cada una, el anillo movible y los posibles lugares donde correrlo
                res.append(self.nuevo_estado(self.colectora(torre,e),proximo,list(e))) #agregamos a res, las alternativas formadas con estos datos
        return res #devolvemos al buscador interno del search el conjunto de sucesores


if __name__ == '__main__':
    EI= (0,0,0) #Estado inicial
    EM= (2,2,2)#Estado meta
    agente= sonsin(EI,EM) #Instanciamos al agente
    path= s.breadth_first_graph_search(agente) #Pedimos que encuentre el camino segun un algoritmo
    if path is None: print 'Sin solucion'
    else:
        print 'Solucionado'
        for m in path.path()[::-1]: print str(m.action) + ":" + str(m.state)
